

package net.jjjshop.job.controller;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.domain.AlipayTradeOrderinfoSyncModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.response.AlipayTradePayResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.result.BaseWxPayResult;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.v3.util.AesUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import net.jjjshop.common.entity.app.App;
import net.jjjshop.common.entity.order.Order;
import net.jjjshop.common.entity.order.OrderCreditPay;
import net.jjjshop.common.entity.user.User;
import net.jjjshop.common.enums.OrderPayStatusEnum;
import net.jjjshop.common.enums.OrderPayTypeEnum;
import net.jjjshop.common.enums.OrderStatusEnum;
import net.jjjshop.common.enums.OrderTypeEnum;
import net.jjjshop.common.factory.paysuccess.type.PaySuccessOrder;
import net.jjjshop.common.factory.paysuccess.type.PaySuccessTypeFactory;
import net.jjjshop.common.factory.product.ProductFactory;
import net.jjjshop.common.service.app.AppService;
import net.jjjshop.common.service.order.OrderCreditPayService;
import net.jjjshop.common.service.user.UserService;
import net.jjjshop.common.util.OrderUtils;
import net.jjjshop.common.util.SettingUtils;
import net.jjjshop.common.util.UserCouponUtils;
import net.jjjshop.common.util.UserUtils;
import net.jjjshop.common.util.alimini.AlipayUtils;
import net.jjjshop.common.vo.order.PayDataVo;
import net.jjjshop.framework.common.api.ApiResult;
import net.jjjshop.framework.common.controller.BaseController;
import net.jjjshop.framework.common.exception.BusinessException;
import net.jjjshop.framework.log.annotation.OperationLog;
import net.jjjshop.framework.util.UUIDUtil;
import net.jjjshop.job.service.order.OrderService;
import org.apache.commons.io.IOUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import static net.jjjshop.common.util.alimini.AliminiConfig.*;

@Slf4j
@Api(value = "index", tags = {"index"})
@RestController
@RequestMapping("/job/notify")
public class NotifyController extends BaseController {

    @Autowired
    private PaySuccessTypeFactory paySuccessTypeFactory;
    @Autowired
    private WxPayService wxPayService;
    @Autowired
    private AppService appService;
    @Autowired
    private AlipayUtils alipayUtils;

    @Autowired
    private OrderService orderService;
    @Autowired
    private SettingUtils settingUtils;
    @Autowired
    private ProductFactory productFactory;
    @Autowired
    private OrderUtils orderUtils;
    @Autowired
    private UserCouponUtils userCouponUtils;
    @Autowired
    private UserUtils userUtils;
    @Autowired
    private UserService userService;

    @Autowired
    private OrderCreditPayService orderCreditPayService;

    /**
     * 支付宝
     *
     * @param request
     * @return
     */
    @RequestMapping(value = "/aliPay", method = RequestMethod.POST)
    @OperationLog(name = "aliPay")
    @ApiOperation(value = "支付宝-支付回调", response = String.class)
    public String aliPay(HttpServletRequest request) throws AlipayApiException {
        //获取支付宝POST过来反馈信息，将异步通知中收到的待验证所有参数都存放到map中
        Map<String, String> params = new HashMap<String, String>();
        Map requestParams = request.getParameterMap();
        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            //乱码解决，这段代码在出现乱码时使用。
            //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            params.put(name, valueStr);
        }
        //调用SDK验证签名
        //公钥验签示例代码
        boolean signVerified = AlipaySignature.rsaCheckV1(params, ALIPAY_PUBLIC_KEY, CHARSET, SIGNTYPE);
        //公钥证书验签示例代码
        //   boolean flag = AlipaySignature.rsaCertCheckV1(params,alipayPublicCertPath,"UTF-8","RSA2");

        if (signVerified) {
            // TODO 验签成功后
            //按照支付结果异步通知中的描述，对支付结果中的业务内容进行1\2\3\4二次校验，校验成功后在response中返回success
            aliPayF(params, OrderPayTypeEnum.ALIPAY);
            return "success";
        } else {
            // TODO 验签失败则记录异常日志，并在response中返回fail.
            return "fail";
        }

    }


    public String aliPayF(Map<String, String> params, OrderPayTypeEnum orderPayTypeEnum) {
        try {
            log.info("支付宝-支付回调");
            // 附加字段
            PaySuccessOrder order = paySuccessTypeFactory.getFactory(OrderTypeEnum.MASTER.getValue()).getOrder(params.get("out_trade_no"));
            if (order.getPayStatus().intValue() == OrderPayStatusEnum.SUCCESS.getValue().intValue()) {
                return WxPayNotifyResponse.success("处理成功!");
            }
            // 处理支付回调
            PayDataVo payDataVo = new PayDataVo();
            payDataVo.setTransaction_id(params.get("trade_no"));
            payDataVo.setCredit_biz_order_id(params.get("credit_biz_order_id"));

//            payDataVo.setAttach("JSONObject.");
            paySuccessTypeFactory.getFactory(OrderTypeEnum.MASTER.getValue())
                    .onPaySuccess(params.get("out_trade_no").toString(), 10, orderPayTypeEnum.getValue(), payDataVo);
            return "处理成功!";
        } catch (Exception e) {
            log.error("支付宝回调结果异常,异常原因:", e);
            return e.getMessage();
        }
    }


    /**
     * 支付宝
     *
     * @param request
     * @return
     */
    @RequestMapping(value = "/creditbizorderChangedNotify", method = RequestMethod.POST)
    @OperationLog(name = "creditbizorderChangedNotify")
    @ApiOperation(value = "支付宝-芝麻先享变更回调", response = String.class)
    public String creditbizorderChangedNotify(HttpServletRequest request) throws AlipayApiException {
        zmxx(request);
        return "success";
    }

    void zmxx(HttpServletRequest request) throws AlipayApiException {
        JSONObject biz_contentJson = alipayUtils.creditbizorderChanged(request);
        log.info("支付宝回调:{}", biz_contentJson.toJSONString());
        biz_contentJson.get("credit_biz_order_id");//信用服务订单号
        biz_contentJson.get("out_order_no");//商户外部单号
        biz_contentJson.get("trade_no");//支付宝交易号
        biz_contentJson.get("order_status");//信用服务订单状态.INIT: 下单状态；TRADE_CLOSED: 订单取消或者交易全额退款； TRADE_FINISHED：扣款成功状态。
        biz_contentJson.get("credit_pay_mode");//下单模式。用以区分订单类型，是普通下单还是信用下单。 信用下单模式取值：creditAdvanceV2
        log.info("支付宝回调数据库:{}", biz_contentJson.toJSONString());
        HashMap<String, String> params = JSONObject.parseObject(biz_contentJson.toJSONString(), HashMap.class);
        if (biz_contentJson.get("order_status").equals("INIT")) {
            //信用下单成功
            aliPayF(params, OrderPayTypeEnum.ALIPAY_XX);
        } else if (biz_contentJson.get("order_status").equals("TRADE_CLOSED")) {
            //订单取消或者交易全额退款
            close(biz_contentJson.get("out_order_no").toString());
        } else if (biz_contentJson.get("order_status").equals("TRADE_FINISHED")) {
            //扣款成功状态
            paySuccessTypeFactory.getFactory(OrderTypeEnum.MASTER.getValue())
                    .onAuthPaySuccess(params.get("out_order_no").toString(), 20, OrderPayTypeEnum.ALIPAY_XX.getValue(), params);

        } else if (biz_contentJson.get("order_status").equals("fund_auth_freeze")) {
            //资金预授权冻结成功
            log.info("支付宝回调-资金预授权冻结成功");



        } else if (biz_contentJson.get("order_status").equals("fund_auth_freeze.closed")) {
            //资金预授权订单关闭
            log.info("支付宝回调-资金预授权订单关闭");

        } else if (biz_contentJson.get("order_status").equals("fund_auth_freeze.init")) {
            //资金预授权订单创建
            log.info("支付宝回调-资金预授权订单创建");
        } else {
            //异常
        }
    }


    /**
     * 未支付订单取消订单或退款
     */
    private void close(String out_order_no) {
        Order order = orderService.getOne(new LambdaQueryWrapper<Order>().eq(Order::getOutOrderNo, out_order_no));
        // 取消订单事件

        // 回退商品库存
        productFactory.getFactory(order.getOrderSource()).backProductStock(orderUtils.getOrderProduct(order.getOrderId()), false);
        // 回退用户优惠券
        if (order.getCouponId() > 0) {
            userCouponUtils.setIsUse(order.getCouponId(), 0);
        }
        // 批量更新订单状态为已取消
        orderService.update(new LambdaUpdateWrapper<Order>().in(Order::getOrderId, order.getOrderId()).set(Order::getOrderStatus, 20)
                .set(Order::getAuthRemark, "授信失败或退款"));
    }

    /**
     * 需要判断订单是否(已发货且扣款完成,才可解冻授权)\(未发货,可解冻授权)
     */
    private void orderClose(String out_order_no) {
        Order order = orderService.getOne(new LambdaQueryWrapper<Order>().eq(Order::getOutOrderNo, out_order_no));
        if(order.getDeliveryStatus().equals("20")&&order.getZmDeductStatus().equals("20")){
            //已发货,并且已扣款
            order.setOrderStatus(30);
            //执行订单完成后操作
            List<Order> orderList = new ArrayList<>();
            orderList.add(order);
            orderUtils.complete(orderList, order.getAppId());
            orderService.updateById(order);
            log.info("完成订单,取消授权:{}"+out_order_no);
        }else if(order.getDeliveryStatus().equals("10")){
            close(out_order_no);
            log.info("关闭订单,取消授权:{}"+out_order_no);
        }else {
            log.error("非法取消授权:{}"+out_order_no);
            close(out_order_no);
        }

    }
    /**
     * 用户确认收货
     * @param orderId
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public Boolean receipt(Integer orderId) {
        Order order = orderService.getById(orderId);
        if (order.getDeliveryStatus() != 20 || order.getReceiptStatus() != 10) {
            throw new BusinessException("该订单不合法");
        }
        order.setReceiptStatus(20);
        order.setReceiptTime(new Date());
        //授信支付需要先判断
        if (!order.getPayType().equals(OrderPayTypeEnum.ALIPAY_MY.getValue()) &&! order.getPayType().equals(OrderPayTypeEnum.ALIPAY_MY.getValue())) {
            order.setOrderStatus(30);
            //执行订单完成后操作
            List<Order> orderList = new ArrayList<>();
            orderList.add(order);
            orderUtils.complete(orderList, order.getAppId());
        }

        return orderService.updateById(order);
    }


    /**
     * 人脸识别回调地址,结果
     *
     * @return
     */
    @RequestMapping(value = "/faceAuthResult", method = RequestMethod.POST)
    @OperationLog(name = "faceAuthResult")
    @ApiOperation(value = "人脸认证结果-支付回调", response = String.class)
    public String faceAuthResult(@RequestBody JSONObject json) {
        log.info("人脸认证结果:{}", json.toJSONString());
        User user = userService.getOne(new LambdaQueryWrapper<User>().eq(User::getIdFaceAuthOrderId, json.getString("orderId")));
        if (user == null) {
            log.info("无此订单号:{}", json.toJSONString());
            return "fail";
        }
        Integer idFaceStatus = 10;
        if (json.getBoolean("success") == true) {
            idFaceStatus = 20;
        } else {
            idFaceStatus = 30;
        }
        userService.update(new LambdaUpdateWrapper<User>().eq(User::getUserId, user.getUserId())
                .set(User::getIdFaceStatus, idFaceStatus).set(User::getIdFaceAuthTime, new Date()));

        return "ok";
    }


    /**
     * 支付宝回调接口
     *
     * @param request
     * @return
     */
    @RequestMapping(value = "/alipayNotify", method = RequestMethod.POST)
    @OperationLog(name = "alipayNotify")
    @ApiOperation(value = "支付宝-芝麻先享变更回调", response = String.class)
    public String alipayNotify(HttpServletRequest request) throws AlipayApiException {
        //获取支付宝POST过来反馈信息，将异步通知中收到的待验证所有参数都存放到map中
        Map<String, String> params = new HashMap<String, String>();
        Map requestParams = request.getParameterMap();
        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            //乱码解决，这段代码在出现乱码时使用。
            //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            params.put(name, valueStr);
        }
        log.info("支付宝回调,通用,{}", JSONObject.toJSONString(params));
        if (params.get("msg_method").equals("zhima.credit.payafteruse.creditbizorder.changed")) {
            log.info("支付宝回调,通用,{}", "芝麻先享");
            zmxx(request);
        } else {
            log.info("支付宝回调,通用,{}", "其他");
        }


        return "success";
    }


    @RequestMapping(value = "/ddeductZMXX", method = RequestMethod.POST)
    @OperationLog(name = "芝麻先享扣款")
    @ApiOperation(value = "芝麻先享扣款", response = String.class)
    public ApiResult<String> deductZMXX(Integer orderId) throws AlipayApiException {
        Order order = orderService.getById(orderId);
        User user = userService.getById(order.getUserId());
        BigDecimal shengyudaikou =order.getPayPrice().subtract(order.getDeductionMoney());
        if (order.getZmDeductStatus()==20||shengyudaikou.compareTo(BigDecimal.ZERO) == 0) {
            return ApiResult.ok(null, "无需扣款,已经扣完");
        }
        OrderCreditPay orderCreditPay = orderCreditPayService.getOne(new LambdaQueryWrapper<OrderCreditPay>()
                .eq(OrderCreditPay::getOrderId, order.getOrderId())
                .eq(OrderCreditPay::getPayStatus, 10)
                .orderByDesc(OrderCreditPay::getCreateTime)
                .last("limit 1"));
        String remark=DateUtil.formatDateTime(new Date()) + "系统请求扣款,金额:" + shengyudaikou+"元;<br/>";
        if (orderCreditPay == null) {
            orderCreditPay = new OrderCreditPay();
            orderCreditPay.setOrderId(orderId);
            orderCreditPay.setOutRequestNo(OrderUtils.geneOrderNo(order.getUserId()));
            orderCreditPay.setPayStatus(10);
            orderCreditPay.setPayPrice(shengyudaikou);
            orderCreditPay.setPayType(order.getPayType());//免押扣款
            orderCreditPay.setOutTradeNo(OrderUtils.geneOrderNo(order.getUserId()));
            orderCreditPay.setRemark(remark+orderCreditPay.getRemark() );
            orderCreditPayService.save(orderCreditPay);
        }else {
            orderCreditPay.setRemark(orderCreditPay.getRemark() +remark);
            orderCreditPayService.updateById(orderCreditPay);
        }
        if (order.getPayType().equals(OrderPayTypeEnum.ALIPAY_XX.getValue())) {
          String s = alipayUtils.tradeOrderPay(user.getOpenId(), order.getPayPrice(), order.getTradeNo(), orderCreditPay.getOutRequestNo());
        } else if (order.getPayType().equals(OrderPayTypeEnum.ALIPAY_MY.getValue())) {
            AlipayTradePayResponse response = alipayUtils.tradePayMY(orderCreditPay.getOutTradeNo(), shengyudaikou, "商品", order.getCreditBizOrderId());
            orderCreditPay.setTradeNo(response.getTradeNo());
            orderCreditPayService.updateById(orderCreditPay);
        }
        orderService.update(new LambdaUpdateWrapper<Order>().eq(Order::getOrderId, order.getOrderId()).set(Order::getAuthRemark, order.getAuthRemark()+remark));
        return ApiResult.ok(null, "请求扣款成功,等待支付宝结果");

    }

    /**
     * 支付宝回调(芝麻免押)接口
     *
     * @param request
     * @return
     */
    @RequestMapping(value = "/alipayZZMYNotify", method = RequestMethod.POST)
    @OperationLog(name = "alipayNotify")
    @ApiOperation(value = "支付宝-芝麻免押回调", response = String.class)
    public String alipayZZMYNotify(HttpServletRequest request) throws AlipayApiException {
        //获取支付宝POST过来反馈信息，将异步通知中收到的待验证所有参数都存放到map中
        HashMap<String, String> params = new HashMap<String, String>();
        Map requestParams = request.getParameterMap();
        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            //乱码解决，这段代码在出现乱码时使用。
            //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            params.put(name, valueStr);
        }
        log.info("支付宝回调,通用,{}", JSONObject.toJSONString(params));
        if (params.get("notify_type").equals("fund_auth_freeze")&&params.get("status").equals("SUCCESS")) {
            //资金预授权冻结成功。
            log.info("支付宝回调,通用,{}", "资金预授权冻结成功。");
            aliPayZZMY(params,OrderPayTypeEnum.ALIPAY_MY);

        } else if(params.get("notify_type").equals("fund_auth_unfreeze")&&params.get("status").equals("SUCCESS")){
            //资金授权订单解冻完结,不需要关闭订单。
            log.info("支付宝回调,通用,{}", "资金授权订单解冻。");
            //需要判断订单是否(已发货且扣款完成,才可解冻授权)\(未发货,可解冻授权)
            orderClose(params.get("out_order_no"));
        } else if(params.get("notify_type").equals("fund_auth_operation_cancel")&&params.get("status").equals("SUCCESS")) {
            log.info("支付宝回调,通用,{}", "资金预授权明细撤销。");

        } else if (params.get("notify_type").equals("trade_status_sync") && params.get("trade_status").equals("TRADE_SUCCESS")) {
            //扣款回调
            log.info("支付宝回调,通用,{}", "扣款回调。");
            //扣款成功状态,芝麻免押用jjjshop_order_credit_pay表来查询
            paySuccessTypeFactory.getFactory(OrderTypeEnum.MASTER.getValue())
                    .onAuthPaySuccess(params.get("out_trade_no").toString(), 20, OrderPayTypeEnum.ALIPAY_MY.getValue(), params);

        }

        return "success";
    }



    public String aliPayZZMY(Map<String, String> params, OrderPayTypeEnum orderPayTypeEnum) {
        try {
            log.info("支付宝-支付回调");
            // 附加字段
            PaySuccessOrder order = paySuccessTypeFactory.getFactory(OrderTypeEnum.MASTER.getValue()).getOrder(params.get("out_order_no"));
            if (order.getPayStatus().intValue() == OrderPayStatusEnum.SUCCESS.getValue().intValue()) {
                return WxPayNotifyResponse.success("处理成功!");
            }
            // 处理支付回调
            PayDataVo payDataVo = new PayDataVo();
            params.get("auth_no");//支付宝资金授权订单号。
            params.get("out_order_no");//商家的资金授权订单号。
            params.get("operation_id");//支付宝的资金操作流水号。
            params.get("out_request_no");//商家资金操作流水号。。
            params.get("operation_type");//资金操作类型，枚举值如下FREEZE：冻结UNFREEZE：解冻。
            params.get("amount");//本次操作冻结的金额。
            params.get("status");//资金预授权明细的状态，枚举值如下：INIT：初始。SUCCESS: 该明细操作成功。CLOSED：该明细操作已关闭。
            params.get("payer_logon_id");//付款方支付宝账号登录号，脱敏。
            params.get("total_freeze_amount");//累计冻结金额。
            params.get("total_unfreeze_amount");//累计解冻金额。。
            params.get("total_pay_amount");//累计支付金额。。。
            params.get("rest_amount");//剩余冻结金额。
            payDataVo.setTransaction_id(params.get("operation_id"));
            payDataVo.setCredit_biz_order_id(params.get("auth_no"));
//            payDataVo.setAttach("JSONObject.");
            paySuccessTypeFactory.getFactory(OrderTypeEnum.MASTER.getValue())
                    .onPaySuccess(params.get("out_order_no").toString(), 10, orderPayTypeEnum.getValue(), payDataVo);
            return "处理成功!";
        } catch (Exception e) {
            log.error("支付宝回调结果异常,异常原因:", e);
            return e.getMessage();
        }
    }

}
